package cn.song.app.controller;


import cn.hutool.json.JSONUtil;
import cn.song.app.config.AlipayConfig;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.*;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

/**
 * 支付宝控制器
 *
 * @author SongRenShuo
 * @date 2023/12/26
 */
@RestController
@RequestMapping("App")
public class AlipayController {

    /**
     * 编码
     */
    private final String ENCODE = "UTF-8";
    @Autowired
    private HttpServletRequest request;

    /**
     * 生成 APP 支付订单信息
     *
     * @return {@link String }
     * @date: 2024/01/27
     * @author SongRenShuo
     */
    @RequestMapping("pay")
    public String pay() throws Exception {
        if (getParameter("WIDout_trade_no") != null) {
            // 商户订单号，商户网站订单系统中唯一订单号，必填
            String out_trade_no = getParameter("WIDout_trade_no");

            /**********************/
            // SDK 公共请求类，包含公共请求参数，以及封装了签名与验签，开发者无需关注签名与验签
            // 调用RSA签名方式
            AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE);
            AlipayTradeWapPayRequest alipay_request = new AlipayTradeWapPayRequest();
            // 设置异步通知地址
            alipay_request.setNotifyUrl(AlipayConfig.NOTIFY_URL);
            // 设置同步地址
            // alipay_request.setReturnUrl(AlipayConfig.return_url);

            // 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
            AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
            // SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
            AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
            model.setBody("我是测试数据");
            model.setSubject("App支付测试Java");
            model.setOutTradeNo(out_trade_no);
            model.setTimeoutExpress("30m");
            model.setTotalAmount("0.01");
            model.setProductCode("QUICK_MSECURITY_PAY");
            request.setBizModel(model);
            request.setNotifyUrl("商户外网可以访问的异步地址");
            try {
                // 这里和普通的接口调用不同，使用的是sdkExecute
                AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
                // 就是orderString 可以直接给客户端请求，无需再做处理。
                String body = response.getBody();
                System.out.println("生成 APP 支付订单信息：" + JSONUtil.formatJsonStr(body));
                return body;
            } catch (AlipayApiException e) {
                e.printStackTrace();
            }
        }
        return "商户订单号不可以为空";
    }

    /**
     * 生成 APP 支付订单信息（证书）
     *
     * @return {@link String }
     * @date: 2024/01/26
     * @author SongRenShuo
     */
    @RequestMapping("payCertificate")
    public String payCertificate() throws Exception {
        if (getParameter("WIDout_trade_no") != null) {
            // 商户订单号，商户网站订单系统中唯一订单号，必填
            String out_trade_no = getParameter("WIDout_trade_no");
            /**********************/

            // 构造client
            CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
            // 设置网关地址
            certAlipayRequest.setServerUrl(AlipayConfig.URL);
            // 设置应用Id
            certAlipayRequest.setAppId(AlipayConfig.APPID);
            // 设置应用私钥
            certAlipayRequest.setPrivateKey(AlipayConfig.RSA_PRIVATE_KEY);
            // 设置请求格式，固定值json
            certAlipayRequest.setFormat(AlipayConfig.FORMAT);
            // 设置字符集
            certAlipayRequest.setCharset(AlipayConfig.CHARSET);
            // 设置签名类型
            certAlipayRequest.setSignType(AlipayConfig.SIGNTYPE);
            // 设置应用公钥证书路径
            certAlipayRequest.setCertPath(AlipayConfig.CERTPATH);
            // 设置支付宝公钥证书路径
            certAlipayRequest.setAlipayPublicCertPath(AlipayConfig.ALIPAY_PUBLI_CCERT_PATH);
            // 设置支付宝根证书路径
            certAlipayRequest.setRootCertPath(AlipayConfig.ALIPAY_ROOT_CERT_PATH);
            // 构造client
            AlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest);
            // 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
            AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
            // SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
            AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
            model.setBody("我是测试数据");
            model.setSubject("App支付测试Java");
            model.setOutTradeNo(out_trade_no);
            model.setTimeoutExpress("30m");
            model.setTotalAmount("0.01");
            model.setProductCode("QUICK_MSECURITY_PAY");
            request.setBizModel(model);
            request.setNotifyUrl(AlipayConfig.NOTIFY_URL_Certificate);
            try {
                // 这里和普通的接口调用不同，使用的是sdkExecute
                AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
                // 就是orderString 可以直接给客户端请求，无需再做处理。
                String body = response.getBody();
                System.out.println("生成 APP 支付订单信息（证书）：" + JSONUtil.formatJsonStr(body));
                return body;
            } catch (AlipayApiException e) {
                e.printStackTrace();
            }
        }
        return "商户订单号不能为空";
    }

    /**
     * 获取参数值
     *
     * @param name 名字
     * @return {@link String }
     * @date: 2024/01/26
     * @author SongRenShuo
     */
    public String getParameter(String name) throws Exception {

        return new String(this.request.getParameter(name).getBytes(ENCODE), ENCODE);
    }
}
